[chore] GitHub Spec Kit 도입 및 헌법 v1.0.0 비준#353
Conversation
- specify CLI 기반 spec-driven development 워크플로우 도입 - .claude/skills/speckit-* 14개 슬래시 커맨드 설치 (Claude Code 연동) - .specify/ 인프라(템플릿/스크립트/git 익스텐션/워크플로우) 추가 - THIP-Server 헌법 v1.0.0 비준 (6개 원칙, 한국어 본문) 계층형 아키텍처 / 커버리지 게이트 테스트 / API 계약 안정성 / 보안 우선 / 관찰 가능성 / 성능 가드 TODO: JaCoCo 임계치, k6 도메인별 임계치 - 머지 룰: 리뷰어 1인 이상 + CI green - 헌법 개정 룰: 백엔드 3인 전원 승인 - .gitignore: .specify 하위 yml 예외 처리 (*.yml 룰 회피)
Walkthrough이 PR은 Spec-Driven Development 워크플로우를 위한 완전한 Spec Kit 프레임워크를 도입합니다. 9개의 새로운 스킬 문서, Git 브랜칭 확장(Bash/PowerShell 스크립트 포함), 공용 유틸리티, 마크다운 템플릿, 프로젝트 헌법을 추가하여 스펙 작성부터 구현 실행 및 분석까지의 전체 라이프사이클을 자동화합니다. ChangesSpec Kit SDD 프레임워크 및 Git 통합
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
Test Results488 tests 488 ✅ 44s ⏱️ Results for commit 2277cb3. |
There was a problem hiding this comment.
Actionable comments posted: 14
🧹 Nitpick comments (18)
.claude/skills/speckit-constitution/SKILL.md (2)
158-158: 💤 Low value파일 끝에 newline 추가 권장
POSIX 및 Git 컨벤션 준수를 위해 파일 마지막에 newline 추가를 권장합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-constitution/SKILL.md at line 158, Add a trailing newline to the end of the SKILL.md file (file: .claude/skills/speckit-constitution/SKILL.md) so the file terminates with a POSIX/Git-compliant newline; simply ensure the last character is a newline (no other content changes).
89-89: 💤 Low value"agent-specific names like CLAUDE only" 표현 명확화 필요
이 라인은 템플릿 파일(
.specify/templates/commands/*.md)에서 에이전트별 이름 참조를 제거하라는 의미로 보이나, 표현이 모호합니다. 현재 스킬 문서 자체는.claude/경로에 있어 Claude 전용이므로, "템플릿 파일에서는 에이전트별 참조 대신 범용 용어 사용" 같은 명확한 표현으로 개선을 권장합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-constitution/SKILL.md at line 89, Replace the ambiguous phrase "agent-specific names like CLAUDE only" with a clear instruction that templates should use generic terminology; update the sentence in SKILL.md to say something like: "Read each command file in `.specify/templates/commands/*.md` (including this one) and replace any agent-specific names (e.g., CLAUDE) with generic terms so templates remain agent-agnostic," ensuring the guidance notes that this skill doc lives in an agent-specific directory but templates themselves must be generic..claude/skills/speckit-clarify/SKILL.md (1)
255-255: 💤 Low value파일 끝에 newline 추가 권장
Git 및 POSIX 컨벤션 준수를 위해 파일 마지막 줄에 newline을 추가하세요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-clarify/SKILL.md at line 255, Add a trailing newline at the end of the file .claude/skills/speckit-clarify/SKILL.md so the file ends with a single terminating newline character (to comply with Git/POSIX conventions); open the file and ensure the last line has a newline and commit the change..claude/skills/speckit-git-remote/SKILL.md (1)
18-20: 💤 Low value펜스드 코드 블록에 언어 지정 권장
Markdown 렌더링 품질 향상 및 린터 경고 해소를 위해 언어 지정을 추가하세요.
🔧 제안 수정
-- If Git is not available, output a warning and return empty: - ``` + ```text [specify] Warning: Git repository not detected; cannot determine remote URL</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In @.claude/skills/speckit-git-remote/SKILL.md around lines 18 - 20, Update the
fenced code block that currently contains "[specify] Warning: Git repository not
detected; cannot determine remote URL" to include a language specifier (e.g.,
add "text" after the opening backticks) so the block becomestext ...,
improving Markdown rendering and satisfying the linter; locate the exact fenced
block with the warning text in SKILL.md and change the opening fence
accordingly.</details> </blockquote></details> <details> <summary>.claude/skills/speckit-analyze/SKILL.md (1)</summary><blockquote> `261-261`: _💤 Low value_ **파일 끝에 newline 추가 권장** POSIX 표준과 Git 컨벤션에 따라 텍스트 파일은 마지막 줄에 newline 문자로 끝나야 합니다. <details> <summary>🔧 제안 수정</summary> 파일 끝(261번째 라인)에 빈 줄 하나 추가: ```diff $ARGUMENTS + ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-analyze/SKILL.md at line 261, Add a single trailing newline character at the end of SKILL.md (file SKILL.md) so the file ends with a blank line per POSIX/Git conventions; simply open SKILL.md and ensure there is one empty newline at the very end of the file. ``` </details> </blockquote></details> <details> <summary>.claude/skills/speckit-checklist/SKILL.md (1)</summary><blockquote> `373-373`: _💤 Low value_ **파일 끝에 newline 추가 권장** POSIX 표준 및 Git 컨벤션 준수를 위해 파일 마지막에 newline 문자 추가를 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-checklist/SKILL.md at line 373, Add a missing trailing newline at the end of SKILL.md: open the SKILL.md file and ensure the final line ends with a single newline character (LF) so the file terminates with '\n' before committing, preserving POSIX/Git conventions. ``` </details> </blockquote></details> <details> <summary>.claude/skills/speckit-implement/SKILL.md (1)</summary><blockquote> `59-59`: _💤 Low value_ **쉘 이스케이프 예제의 보안 주의사항을 문서화하세요.** Line 59에서 `'I'\''m Groot'` 형태의 쉘 이스케이프 예제를 제공하고 있습니다. 이 예제는 여러 SKILL.md 파일에서 반복적으로 사용되는데, 사용자가 임의의 입력을 이 방식으로 이스케이프할 때 발생할 수 있는 주의사항을 명시하는 것이 좋습니다. <details> <summary>📝 제안: 보안 주의사항 추가</summary> ```diff -1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). +1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). **Security Note**: Only use this escaping for trusted input; validate and sanitize user-provided arguments before shell execution. ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/speckit-implement/SKILL.md at line 59, Add a short security note next to the single-quote escape example ('I'\''m Groot') in SKILL.md explaining the risks of naive shell-escaping user input (command injection, word-splitting, unexpected expansion), and instruct maintainers to prefer safe alternatives when handling untrusted strings: use array args or pass data via stdin, use language/library-specific escaping helpers, or use printf %q / proper quoting functions rather than manually concatenating quotes; reference the check-prerequisites invocation (.specify/scripts/bash/check-prerequisites.sh) and the exact example ('I'\''m Groot') so readers can locate and replace unsafe usages. ``` </details> </blockquote></details> <details> <summary>.specify/extensions/git/commands/speckit.git.initialize.md (1)</summary><blockquote> `16-18`: _⚡ Quick win_ **폴백 커밋 메시지와 설정값(`init_commit_message`)을 일치시켜 주세요.** 현재 폴백 경로는 고정 메시지를 사용해, 확장 설정의 `init_commit_message` 문서 계약과 어긋납니다. 폴백도 동일 설정을 읽거나, 최소한 “폴백은 고정 메시지”라고 명시해 혼선을 줄이는 게 좋습니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/extensions/git/commands/speckit.git.initialize.md around lines 16 - 18, The fallback Git commands currently use a hardcoded commit message and must be made consistent with the extension setting init_commit_message; update the fallback examples (the Bash and PowerShell lines that show git init && git add . && git commit -m "Initial commit from Specify template" and git init; git add .; git commit -m "Initial commit from Specify template") so they either reference the init_commit_message configuration (e.g., replace the literal message with a placeholder that indicates the message is read from init_commit_message) or explicitly state that the fallback uses a fixed message; ensure the wording clearly matches the documented contract for init_commit_message. ``` </details> </blockquote></details> <details> <summary>.specify/memory/constitution.md (2)</summary><blockquote> `149-149`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준 준수 및 프로젝트 일관성을 위해 파일 끝에 newline 문자를 추가하는 것을 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/memory/constitution.md at line 149, The file constitution.md is missing a trailing newline at EOF; open the file (constitution.md) and add a single newline character at the end so the file ends with '\n' to comply with POSIX and project conventions. ``` </details> --- `1-31`: _⚡ Quick win_ **Sync Impact Report의 위치를 재고하세요.** Sync Impact Report가 문서 최상단에 HTML 주석으로 포함되어 있어, 헌법 문서를 처음 읽는 사람에게는 혼란을 줄 수 있습니다. 이 메타데이터가 버전 관리에 중요하다면, 문서 하단으로 이동하거나 별도의 CHANGELOG 파일로 분리하는 것을 고려하세요. 현재 위치에서 유지한다면, 주석 상단에 간단한 설명을 추가하여 목적을 명확히 하는 것이 좋습니다: ```markdown <!-- This Sync Impact Report tracks version changes and their impact on related artifacts. It is maintained for governance and audit purposes. ================== ``` <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/memory/constitution.md around lines 1 - 31, The HTML "Sync Impact Report" comment block at the top of the constitution should be moved out of the document head to avoid confusing first-time readers: either relocate that entire <!-- Sync Impact Report ... --> block to the bottom of the file or extract it into a separate governance/CHANGELOG artifact; if you choose to keep it at the top, prepend a short explanatory comment line (e.g., "This Sync Impact Report tracks version changes and is maintained for governance and audit purposes.") immediately above the existing HTML comment so readers understand its purpose. Ensure you update the existing comment block named "Sync Impact Report" accordingly and run a quick preview to confirm the document renders without unexpected top-of-file noise. ``` </details> </blockquote></details> <details> <summary>.specify/templates/tasks-template.md (1)</summary><blockquote> `253-253`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준 준수 및 프로젝트 일관성을 위해 파일 끝에 newline 문자를 추가하는 것을 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/tasks-template.md at line 253, Add a trailing newline character at the end of .specify/templates/tasks-template.md (i.e., ensure the file ends with a single '\n') to comply with POSIX and project consistency; update the file so the last line is terminated rather than EOF immediately after the last character. ``` </details> </blockquote></details> <details> <summary>.specify/templates/constitution-template.md (1)</summary><blockquote> `51-51`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준 준수 및 프로젝트 일관성을 위해 파일 끝에 newline 문자를 추가하는 것을 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/constitution-template.md at line 51, constitution-template.md currently lacks a trailing newline; open the file and ensure the final character is a single newline (i.e., the file ends with '\n') so it conforms to POSIX and project conventions, avoiding adding extra blank lines beyond that. ``` </details> </blockquote></details> <details> <summary>.specify/templates/plan-template.md (2)</summary><blockquote> `114-114`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준 준수 및 프로젝트 일관성을 위해 파일 끝에 newline 문자를 추가하는 것을 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/plan-template.md at line 114, The file plan-template.md is missing a trailing newline at EOF; open plan-template.md and add a single newline character at the end of the file so the file ends with a newline (POSIX-compliant EOF newline). ``` </details> --- `60-101`: _⚡ Quick win_ **"Option labels" 지시사항을 더 명확하게 표현하세요.** 라인 63-64의 주석에서 "The delivered plan must not include Option labels"라고 명시하고 있으나, 실제 예시에서는 `# [REMOVE IF UNUSED] Option 1/2/3` 형태로 표시되어 있습니다. "Option labels"가 `Option 1`, `Option 2` 등의 텍스트를 의미하는지, 아니면 `[REMOVE IF UNUSED]` 표식까지 포함하는지 명확하지 않을 수 있습니다. 사용자가 어느 부분을 제거해야 하는지 더 명확하게 안내하는 것을 고려하세요. 예시: ```markdown <!-- The delivered plan must not include unused options or "[REMOVE IF UNUSED]" markers. Delete entire option sections that don't apply to your project structure. --> ``` <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/plan-template.md around lines 60 - 101, Update the placeholder comment that precedes the example tree (the HTML comment containing "# [REMOVE IF UNUSED] Option 1/2/3" and the example layouts) to explicitly require removal of both the "Option X" labels and any "[REMOVE IF UNUSED]" markers and to delete entire unused option sections; replace the current ambiguous line ("The delivered plan must not include Option labels") with a clearer instruction such as: "The delivered plan must not include unused options or '[REMOVE IF UNUSED]' markers — delete the entire option section (including the 'Option X' label and any '[REMOVE IF UNUSED]' text) if it does not apply to your project." Ensure this updated wording is placed where the current placeholder comment appears so authors remove whole option blocks like "# [REMOVE IF UNUSED] Option 1" rather than leaving fragments. ``` </details> </blockquote></details> <details> <summary>.specify/templates/spec-template.md (1)</summary><blockquote> `132-132`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준 준수 및 프로젝트 일관성을 위해 파일 끝에 newline 문자를 추가하는 것을 권장합니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/spec-template.md at line 132, spec-template.md의 끝에 newline 문자를 추가하세요: 파일의 최종 바이트가 개행 문자('\n', LF)로 끝나도록 수정하고 불필요한 추가 공백 라인을 만들지 마세요; 편집기에서 파일을 열어 맨 마지막 줄 끝에 단일 개행을 추가하고 저장하면 됩니다. ``` </details> </blockquote></details> <details> <summary>.specify/templates/checklist-template.md (1)</summary><blockquote> `41-41`: _⚡ Quick win_ **파일 끝에 newline을 추가하세요.** POSIX 표준에 따르면 텍스트 파일은 newline 문자로 끝나야 합니다. 일부 Git 도구가 이를 경고할 수 있으며, 프로젝트 전체의 일관성 유지를 위해 추가하는 것이 좋습니다. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/templates/checklist-template.md at line 41, Add a single trailing newline at the end of checklist-template.md so the file ends with a newline character (POSIX-compliant); open the template (checklist-template.md) and ensure the last line is followed by one newline, save the file, and commit the change without altering other content. ``` </details> </blockquote></details> <details> <summary>.specify/extensions/git/scripts/powershell/create-new-feature.ps1 (1)</summary><blockquote> `106-109`: _⚡ Quick win_ **`GIT_TERMINAL_PROMPT`는 이전 값을 복원하는 방식이 더 안전합니다.** 현재는 강제로 `$null`로 되돌려, 기존 세션값을 덮어쓸 수 있습니다. 기존 값을 저장/복원해 부작용을 줄여주세요. <details> <summary>수정 제안</summary> ```diff - $env:GIT_TERMINAL_PROMPT = '0' - $refs = git ls-remote --heads $remote 2>$null - $env:GIT_TERMINAL_PROMPT = $null + $previousPrompt = $env:GIT_TERMINAL_PROMPT + try { + $env:GIT_TERMINAL_PROMPT = '0' + $refs = git ls-remote --heads $remote 2>$null + } finally { + $env:GIT_TERMINAL_PROMPT = $previousPrompt + } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/extensions/git/scripts/powershell/create-new-feature.ps1 around lines 106 - 109, Save the original environment value before mutating it and restore it afterward instead of unconditionally setting $env:GIT_TERMINAL_PROMPT = $null; specifically, capture the current $env:GIT_TERMINAL_PROMPT into a temporary variable (e.g. $prevPrompt), set $env:GIT_TERMINAL_PROMPT = '0' before running git ls-remote (which populates $refs and affects $LASTEXITCODE), then after the git call restore $env:GIT_TERMINAL_PROMPT to $prevPrompt (or remove the env var if it was originally absent) so you avoid overwriting an existing session value. ``` </details> </blockquote></details> <details> <summary>.specify/scripts/bash/setup-tasks.sh (1)</summary><blockquote> `58-63`: _⚡ Quick win_ **`resolve_template` 실패를 `|| true`로 삼키지 마세요.** 현재는 템플릿 미존재와 실행 오류를 구분하지 못해 장애 원인 파악이 어려워집니다. 실행 실패는 즉시 별도 에러로 종료하고, “not found”는 후속 존재성 체크로 분리하는 편이 안전합니다. <details> <summary>수정 예시 diff</summary> ```diff -TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT") || true -if [[ -z "$TASKS_TEMPLATE" ]] || [[ ! -f "$TASKS_TEMPLATE" ]]; then +if ! TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT"); then + echo "ERROR: Failed to resolve tasks-template due to resolver execution error" >&2 + exit 1 +fi +if [[ -z "$TASKS_TEMPLATE" ]] || [[ ! -f "$TASKS_TEMPLATE" ]]; then echo "ERROR: Could not resolve required tasks-template from the template override stack for $REPO_ROOT" >&2 echo "Template 'tasks-template' was not found in any supported location (overrides, presets, extensions, or shared core). Add an override at .specify/templates/overrides/tasks-template.md, or run 'specify init' / reinstall shared infra to restore the core .specify/templates/tasks-template.md template." >&2 exit 1 fi ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.specify/scripts/bash/setup-tasks.sh around lines 58 - 63, The current call to resolve_template in TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT") || true swallows execution failures; remove the "|| true" and instead capture the command's exit status immediately after calling resolve_template (use the TASKS_TEMPLATE assignment), if resolve_template returns non‑zero then log a clear error and exit, otherwise proceed to check if TASKS_TEMPLATE is empty or the file doesn't exist and handle the "not found" case with the existing message; update the block around the resolve_template invocation and the TASKS_TEMPLATE variable check to separate execution errors from missing-template errors. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.Inline comments:
In @.specify/extensions/git/commands/speckit.git.remote.md:
- Around line 13-15: Add a language identifier to the fenced code block that
contains "[specify] Warning: Git repository not detected; cannot determine
remote URL" so markdownlint MD040 is satisfied (for example change the fence
fromtotext); locate the fenced block in the file and update the opening
backticks to include the language token.In @.specify/extensions/git/commands/speckit.git.validate.md:
- Around line 13-15: Add a language identifier to the fenced code block
containing "[specify] Warning: Git repository not detected; skipped branch
validation" (replace the openingwithtext) so the markdown linter rule
MD040 is satisfied and the warning example is treated as plain text.In @.specify/extensions/git/config-template.yml:
- Around line 11-13: 주석의 설명이 현재 YAML 구조와 맞지 않습니다: update the comment for the
auto_commit entry to reflect that auto_commit is an object whose per-command
entries are objects with an enabled boolean and an optional message, not simple
true/false keys; reference the auto_commit key and mention the subkeys enabled
and message (e.g., "auto_commit entries: enabled: true|false, message: 'text'")
so readers know the actual schema and can set per-command messages correctly.In @.specify/extensions/git/scripts/bash/auto-commit.sh:
- Around line 136-138: The script currently runs git add . which stages every
local change; update auto-commit.sh to stage only Spec Kit–managed files by
introducing/using a files-to-commit variable (e.g. _files_to_commit) or accept a
list of files from the caller and replace the git add . call with git add --
$_files_to_commit (falling back to a safe default such as the .specify
directory), then use the existing git commit -q -m "$_commit_msg" call; update
any surrounding error messages to reference the new variable and ensure any code
paths that previously relied on git add . now populate _files_to_commit
appropriately.In @.specify/extensions/git/scripts/powershell/auto-commit.ps1:
- Around line 86-87: Escape the $EventName before inserting it into regex
matches to avoid special-character misinterpretation: replace usages where you
build regexes like$line -match "^\s+$ {EventName}:" and the later match for
message (the patterns around lines using $EventName and -match) with a version
that uses [regex]::Escape($EventName) (or equivalent) so the literal event name
is matched; update both occurrences (the initial event header match and the
subsequent message/enabled checks) to use the escaped value.In @.specify/extensions/git/scripts/powershell/create-new-feature.ps1:
- Around line 285-307: Add an explicit validation guard to reject negative
values for the $Number parameter: after parameter parsing (or at least before
the block that checks $Number and computes $featureNum) add a check like if
($Number -lt 0) { Write-Error "[specify] Invalid -Number: must be non-negative";
exit 1 } so negative inputs are rejected even when $Timestamp is used or when
$Number would later be adjusted; reference the $Number variable and the existing
block that computes $featureNum/$branchName to find the correct insertion point.In @.specify/extensions/git/scripts/powershell/git-common.ps1:
- Around line 44-48: $isSequential currently uses the regex '^[0-9]{3,}-' which
allows a bare numeric prefix like "001-" without any slug; update the branch
validation to require at least one slug character after the hyphen (e.g. change
the $isSequential regex to something like '^[0-9]{3,}-.+' or a stricter slug
pattern) and also make the timestamp-prefixed check require a slug (change
'^\d{8}-\d{6}-' to '^\d{8}-\d{6}-.+'); adjust the checks that reference
$isSequential and Branch so they fail when there is no slug after the hyphen.In @.specify/feature.json:
- Line 2:
specs/001-feed-features디렉터리가 자동 생성되지 않아 검사에서 실패하므로
.specify/scripts/bash/common.sh의 흐름을 수정하여 feature.json에서 읽은 경로를 검증하기 전에 디렉터리를
생성하도록 하세요: read_feature_json_feature_directory()로 읽은 값(예: feature_directory 또는
변수명 _fd)을 사용해 검사 전에 mkdir -p "$_fd"를 호출하여 경로를 만들고, 그 다음에
feature_json_matches_feature_dir()에서 기존의 [[ -d "$_fd" ]] 검증을 수행하도록 변경해 주세요.In @.specify/scripts/bash/check-prerequisites.sh:
- Around line 81-88: The branch validation is run before paths-only early exit,
so --paths-only still triggers check_feature_branch; move the
check_feature_branch call to after the PATHS_ONLY conditional (so it only runs
when PATHS_ONLY is false). Specifically, keep the get_feature_paths / eval /
unset sequence as-is, then immediately handle the PATHS_ONLY early return (using
PATHS_ONLY to print paths/JSON and exit), and only after that call
check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1; this ensures
get_feature_paths and PATHS_ONLY behavior remain unchanged while branch
validation is skipped in paths-only mode.In @.specify/scripts/bash/common.sh:
- Around line 268-288: The current resolution of feature_dir (from
SPECIFY_FEATURE_DIRECTORY, read_feature_json_feature_directory, or
find_feature_dir_by_prefix) does not enforce that the final path is inside
repo_root; a malicious or relative value (../ or absolute) can escape the repo
and allow unsafe file operations. After any assignment to feature_dir (including
the branches using SPECIFY_FEATURE_DIRECTORY, the
read_feature_json_feature_directory result, and the find_feature_dir_by_prefix
fallback) normalize to an absolute path and then validate that feature_dir is a
descendant of repo_root (e.g. by resolving both to absolute, canonical paths and
ensuring feature_dir starts with "$repo_root/"); if validation fails, print an
error and return non‑zero instead of continuing. Ensure this check is applied to
the code paths using variables/functions: SPECIFY_FEATURE_DIRECTORY,
read_feature_json_feature_directory, find_feature_dir_by_prefix, feature_dir,
repo_root, and current_branch.In @.specify/scripts/bash/create-new-feature.sh:
- Around line 39-51: When handling the --number option (the branch-number
parsing block that assigns BRANCH_NUMBER from next_arg), validate that next_arg
is a numeric string before assigning it to BRANCH_NUMBER; if it fails (e.g. not
matching a digits-only regex), print the same error and exit as when the value
is missing. Specifically, in the block that uses i, next_arg and sets
BRANCH_NUMBER, add a numeric check (digits-only, e.g. /^[0-9]+$/) and reject
non-numeric values to avoid the later arithmetic expansion error
(10#$BRANCH_NUMBER) — mirror the validation used in the extension script for
consistency.In @.specify/scripts/bash/setup-plan.sh:
- Around line 43-52: The current setup-plan.sh unconditionally overwrites
IMPL_PLAN using TEMPLATE (TEMPLATE=$(resolve_template "plan-template"
"$REPO_ROOT") ... cp "$TEMPLATE" "$IMPL_PLAN"), which destroys user edits;
change the logic in setup-plan.sh to only copy the template when IMPL_PLAN does
not exist or when an explicit force option is passed (e.g., check a parsed
--force flag or env var like FORCE_PLAN), keep the resolve_template/TEMPLATE
check, and if IMPL_PLAN exists and force is not set skip copying and print a
message that the existing plan is preserved; ensure the code paths reference
TEMPLATE, resolve_template, and IMPL_PLAN so reviewers can find the updated
conditional and option parsing.In @.specify/workflows/speckit/workflow.yml:
- Around line 23-26: 워크플로우에 선언된 입력값
scope(enum
["full","backend-only","frontend-only"])가 실제로 사용되지 않아 동작에 영향이 없으니, either remove
thescopeinput or wire it into the existing steps by using{{ inputs.scope }}in conditional expressions; specifically update the steps that currently
reference{{ inputs.integration }}and{{ inputs.spec }}to include
if/whenconditions (e.g., check{{ inputs.scope }} == 'backend-only',== 'frontend-only'or== 'full') so backend-only tasks skip in frontend-only
runs and vice versa, or delete thescopedeclaration if you choose not to
support scoping.In
@CLAUDE.md:
- Around line 1-4: 문구 "read the current plan" in CLAUDE.md is ambiguous; update
that line to point to a concrete plan location (e.g. replace or augment "read
the current plan" with a specific path like.specify/plan.mdor a dynamic
pattern such as.specify/features/{feature-id}/plan.md), or add a short
comment explaining the Spec Kit convention if the path is implicit, ensuring the
exact phrase "read the current plan" is modified so Claude knows where to find
the plan.
Nitpick comments:
In @.claude/skills/speckit-analyze/SKILL.md:
- Line 261: Add a single trailing newline character at the end of SKILL.md (file
SKILL.md) so the file ends with a blank line per POSIX/Git conventions; simply
open SKILL.md and ensure there is one empty newline at the very end of the file.In @.claude/skills/speckit-checklist/SKILL.md:
- Line 373: Add a missing trailing newline at the end of SKILL.md: open the
SKILL.md file and ensure the final line ends with a single newline character
(LF) so the file terminates with '\n' before committing, preserving POSIX/Git
conventions.In @.claude/skills/speckit-clarify/SKILL.md:
- Line 255: Add a trailing newline at the end of the file
.claude/skills/speckit-clarify/SKILL.md so the file ends with a single
terminating newline character (to comply with Git/POSIX conventions); open the
file and ensure the last line has a newline and commit the change.In @.claude/skills/speckit-constitution/SKILL.md:
- Line 158: Add a trailing newline to the end of the SKILL.md file (file:
.claude/skills/speckit-constitution/SKILL.md) so the file terminates with a
POSIX/Git-compliant newline; simply ensure the last character is a newline (no
other content changes).- Line 89: Replace the ambiguous phrase "agent-specific names like CLAUDE only"
with a clear instruction that templates should use generic terminology; update
the sentence in SKILL.md to say something like: "Read each command file in
.specify/templates/commands/*.md(including this one) and replace any
agent-specific names (e.g., CLAUDE) with generic terms so templates remain
agent-agnostic," ensuring the guidance notes that this skill doc lives in an
agent-specific directory but templates themselves must be generic.In @.claude/skills/speckit-git-remote/SKILL.md:
- Around line 18-20: Update the fenced code block that currently contains
"[specify] Warning: Git repository not detected; cannot determine remote URL" to
include a language specifier (e.g., add "text" after the opening backticks) so
the block becomestext ..., improving Markdown rendering and satisfying
the linter; locate the exact fenced block with the warning text in SKILL.md and
change the opening fence accordingly.In @.claude/skills/speckit-implement/SKILL.md:
- Line 59: Add a short security note next to the single-quote escape example
('I'''m Groot') in SKILL.md explaining the risks of naive shell-escaping user
input (command injection, word-splitting, unexpected expansion), and instruct
maintainers to prefer safe alternatives when handling untrusted strings: use
array args or pass data via stdin, use language/library-specific escaping
helpers, or use printf %q / proper quoting functions rather than manually
concatenating quotes; reference the check-prerequisites invocation
(.specify/scripts/bash/check-prerequisites.sh) and the exact example ('I'''m
Groot') so readers can locate and replace unsafe usages.In @.specify/extensions/git/commands/speckit.git.initialize.md:
- Around line 16-18: The fallback Git commands currently use a hardcoded commit
message and must be made consistent with the extension setting
init_commit_message; update the fallback examples (the Bash and PowerShell lines
that show git init && git add . && git commit -m "Initial commit from Specify
template" and git init; git add .; git commit -m "Initial commit from Specify
template") so they either reference the init_commit_message configuration (e.g.,
replace the literal message with a placeholder that indicates the message is
read from init_commit_message) or explicitly state that the fallback uses a
fixed message; ensure the wording clearly matches the documented contract for
init_commit_message.In @.specify/extensions/git/scripts/powershell/create-new-feature.ps1:
- Around line 106-109: Save the original environment value before mutating it
and restore it afterward instead of unconditionally setting
$env:GIT_TERMINAL_PROMPT = $null; specifically, capture the current
$env:GIT_TERMINAL_PROMPT into a temporary variable (e.g. $prevPrompt), set
$env:GIT_TERMINAL_PROMPT = '0' before running git ls-remote (which populates
$refs and affects $LASTEXITCODE), then after the git call restore
$env:GIT_TERMINAL_PROMPT to $prevPrompt (or remove the env var if it was
originally absent) so you avoid overwriting an existing session value.In @.specify/memory/constitution.md:
- Line 149: The file constitution.md is missing a trailing newline at EOF; open
the file (constitution.md) and add a single newline character at the end so the
file ends with '\n' to comply with POSIX and project conventions.- Around line 1-31: The HTML "Sync Impact Report" comment block at the top of
the constitution should be moved out of the document head to avoid confusing
first-time readers: either relocate that entire
block to the bottom of the file or extract it into a separate
governance/CHANGELOG artifact; if you choose to keep it at the top, prepend a
short explanatory comment line (e.g., "This Sync Impact Report tracks version
changes and is maintained for governance and audit purposes.") immediately above
the existing HTML comment so readers understand its purpose. Ensure you update
the existing comment block named "Sync Impact Report" accordingly and run a
quick preview to confirm the document renders without unexpected top-of-file
noise.In @.specify/scripts/bash/setup-tasks.sh:
- Around line 58-63: The current call to resolve_template in
TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT") || true
swallows execution failures; remove the "|| true" and instead capture the
command's exit status immediately after calling resolve_template (use the
TASKS_TEMPLATE assignment), if resolve_template returns non‑zero then log a
clear error and exit, otherwise proceed to check if TASKS_TEMPLATE is empty or
the file doesn't exist and handle the "not found" case with the existing
message; update the block around the resolve_template invocation and the
TASKS_TEMPLATE variable check to separate execution errors from missing-template
errors.In @.specify/templates/checklist-template.md:
- Line 41: Add a single trailing newline at the end of checklist-template.md so
the file ends with a newline character (POSIX-compliant); open the template
(checklist-template.md) and ensure the last line is followed by one newline,
save the file, and commit the change without altering other content.In @.specify/templates/constitution-template.md:
- Line 51: constitution-template.md currently lacks a trailing newline; open the
file and ensure the final character is a single newline (i.e., the file ends
with '\n') so it conforms to POSIX and project conventions, avoiding adding
extra blank lines beyond that.In @.specify/templates/plan-template.md:
- Line 114: The file plan-template.md is missing a trailing newline at EOF; open
plan-template.md and add a single newline character at the end of the file so
the file ends with a newline (POSIX-compliant EOF newline).- Around line 60-101: Update the placeholder comment that precedes the example
tree (the HTML comment containing "# [REMOVE IF UNUSED] Option 1/2/3" and the
example layouts) to explicitly require removal of both the "Option X" labels and
any "[REMOVE IF UNUSED]" markers and to delete entire unused option sections;
replace the current ambiguous line ("The delivered plan must not include Option
labels") with a clearer instruction such as: "The delivered plan must not
include unused options or '[REMOVE IF UNUSED]' markers — delete the entire
option section (including the 'Option X' label and any '[REMOVE IF UNUSED]'
text) if it does not apply to your project." Ensure this updated wording is
placed where the current placeholder comment appears so authors remove whole
option blocks like "# [REMOVE IF UNUSED] Option 1" rather than leaving
fragments.In @.specify/templates/spec-template.md:
- Line 132: spec-template.md의 끝에 newline 문자를 추가하세요: 파일의 최종 바이트가 개행 문자('\n', LF)로
끝나도록 수정하고 불필요한 추가 공백 라인을 만들지 마세요; 편집기에서 파일을 열어 맨 마지막 줄 끝에 단일 개행을 추가하고 저장하면 됩니다.In @.specify/templates/tasks-template.md:
- Line 253: Add a trailing newline character at the end of
.specify/templates/tasks-template.md (i.e., ensure the file ends with a single
'\n') to comply with POSIX and project consistency; update the file so the last
line is terminated rather than EOF immediately after the last character.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Repository UI **Review profile**: CHILL **Plan**: Pro **Run ID**: `cd8673b2-ef88-4d01-b8f6-9c4b7fdb5fe0` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 9e87db09d28556ea50b774c512c268a1a0f224a9 and 2277cb31126b9dc47e8ade30e636b4513c01d8d2. </details> <details> <summary>📒 Files selected for processing (53)</summary> * `.claude/skills/speckit-analyze/SKILL.md` * `.claude/skills/speckit-checklist/SKILL.md` * `.claude/skills/speckit-clarify/SKILL.md` * `.claude/skills/speckit-constitution/SKILL.md` * `.claude/skills/speckit-git-commit/SKILL.md` * `.claude/skills/speckit-git-feature/SKILL.md` * `.claude/skills/speckit-git-initialize/SKILL.md` * `.claude/skills/speckit-git-remote/SKILL.md` * `.claude/skills/speckit-git-validate/SKILL.md` * `.claude/skills/speckit-implement/SKILL.md` * `.claude/skills/speckit-plan/SKILL.md` * `.claude/skills/speckit-specify/SKILL.md` * `.claude/skills/speckit-tasks/SKILL.md` * `.claude/skills/speckit-taskstoissues/SKILL.md` * `.gitignore` * `.specify/extensions.yml` * `.specify/extensions/.registry` * `.specify/extensions/git/README.md` * `.specify/extensions/git/commands/speckit.git.commit.md` * `.specify/extensions/git/commands/speckit.git.feature.md` * `.specify/extensions/git/commands/speckit.git.initialize.md` * `.specify/extensions/git/commands/speckit.git.remote.md` * `.specify/extensions/git/commands/speckit.git.validate.md` * `.specify/extensions/git/config-template.yml` * `.specify/extensions/git/extension.yml` * `.specify/extensions/git/git-config.yml` * `.specify/extensions/git/scripts/bash/auto-commit.sh` * `.specify/extensions/git/scripts/bash/create-new-feature.sh` * `.specify/extensions/git/scripts/bash/git-common.sh` * `.specify/extensions/git/scripts/bash/initialize-repo.sh` * `.specify/extensions/git/scripts/powershell/auto-commit.ps1` * `.specify/extensions/git/scripts/powershell/create-new-feature.ps1` * `.specify/extensions/git/scripts/powershell/git-common.ps1` * `.specify/extensions/git/scripts/powershell/initialize-repo.ps1` * `.specify/feature.json` * `.specify/init-options.json` * `.specify/integration.json` * `.specify/integrations/claude.manifest.json` * `.specify/integrations/speckit.manifest.json` * `.specify/memory/constitution.md` * `.specify/scripts/bash/check-prerequisites.sh` * `.specify/scripts/bash/common.sh` * `.specify/scripts/bash/create-new-feature.sh` * `.specify/scripts/bash/setup-plan.sh` * `.specify/scripts/bash/setup-tasks.sh` * `.specify/templates/checklist-template.md` * `.specify/templates/constitution-template.md` * `.specify/templates/plan-template.md` * `.specify/templates/spec-template.md` * `.specify/templates/tasks-template.md` * `.specify/workflows/speckit/workflow.yml` * `.specify/workflows/workflow-registry.json` * `CLAUDE.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| ``` | ||
| [specify] Warning: Git repository not detected; cannot determine remote URL | ||
| ``` |
There was a problem hiding this comment.
코드 펜스에 언어 식별자를 지정해 주세요.
Line 13의 fenced block에 언어가 없어 markdownlint(MD040) 경고가 발생합니다.
수정 예시
- ```
+ ```text
[specify] Warning: Git repository not detected; cannot determine remote URL</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 13-13: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/extensions/git/commands/speckit.git.remote.md around lines 13 - 15,
Add a language identifier to the fenced code block that contains "[specify]
Warning: Git repository not detected; cannot determine remote URL" so
markdownlint MD040 is satisfied (for example change the fence from ``` to
```text); locate the fenced block in the file and update the opening backticks
to include the language token.
| ``` | ||
| [specify] Warning: Git repository not detected; skipped branch validation | ||
| ``` |
There was a problem hiding this comment.
코드 펜스 언어 누락(MD040)을 수정해 주세요.
Line 13의 fenced block에 언어 식별자를 추가하면 lint 경고를 제거할 수 있습니다.
수정 예시
- ```
+ ```text
[specify] Warning: Git repository not detected; skipped branch validation</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 13-13: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/extensions/git/commands/speckit.git.validate.md around lines 13 -
15, Add a language identifier to the fenced code block containing "[specify]
Warning: Git repository not detected; skipped branch validation" (replace the
opening ``` with ```text) so the markdown linter rule MD040 is satisfied and the
warning example is treated as plain text.
| # Set "default" to enable for all commands, then override per-command. | ||
| # Each key can be true/false. Message is customizable per-command. | ||
| auto_commit: |
There was a problem hiding this comment.
auto_commit 스키마 설명 주석을 실제 구조와 맞춰 주세요.
Line 12의 “Each key can be true/false”는 현재 YAML 구조(enabled, message 객체)와 불일치합니다. 잘못된 설정 작성으로 이어질 수 있습니다.
수정 예시
-# Each key can be true/false. Message is customizable per-command.
+# Each command key uses an object: { enabled: <bool>, message: <string> }.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Set "default" to enable for all commands, then override per-command. | |
| # Each key can be true/false. Message is customizable per-command. | |
| auto_commit: | |
| # Set "default" to enable for all commands, then override per-command. | |
| # Each command key uses an object: { enabled: <bool>, message: <string> }. | |
| auto_commit: |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/extensions/git/config-template.yml around lines 11 - 13, 주석의 설명이 현재
YAML 구조와 맞지 않습니다: update the comment for the auto_commit entry to reflect that
auto_commit is an object whose per-command entries are objects with an enabled
boolean and an optional message, not simple true/false keys; reference the
auto_commit key and mention the subkeys enabled and message (e.g., "auto_commit
entries: enabled: true|false, message: 'text'") so readers know the actual
schema and can set per-command messages correctly.
| # Stage and commit | ||
| _git_out=$(git add . 2>&1) || { echo "[specify] Error: git add failed: $_git_out" >&2; exit 1; } | ||
| _git_out=$(git commit -q -m "$_commit_msg" 2>&1) || { echo "[specify] Error: git commit failed: $_git_out" >&2; exit 1; } |
There was a problem hiding this comment.
자동 커밋이 저장소 전체의 미관련 변경까지 함께 올립니다.
여기서 git add .를 쓰면 Spec Kit 명령이 건드리지 않은 로컬 수정, 새 파일, 실수로 남겨둔 민감 파일까지 한 커밋에 섞일 수 있습니다. 이 훅은 최소한 Spec Kit가 관리하는 경로만 스테이징하거나, 호출 측에서 변경 파일 목록을 넘겨받아 그 목록만 커밋해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/extensions/git/scripts/bash/auto-commit.sh around lines 136 - 138,
The script currently runs git add . which stages every local change; update
auto-commit.sh to stage only Spec Kit–managed files by introducing/using a
files-to-commit variable (e.g. _files_to_commit) or accept a list of files from
the caller and replace the git add . call with git add -- $_files_to_commit
(falling back to a safe default such as the .specify directory), then use the
existing git commit -q -m "$_commit_msg" call; update any surrounding error
messages to reference the new variable and ensure any code paths that previously
relied on git add . now populate _files_to_commit appropriately.
| if ($line -match "^\s+${EventName}:") { | ||
| $inEvent = $true |
There was a problem hiding this comment.
$EventName를 정규식에 그대로 넣으면 이벤트 매칭이 오작동할 수 있습니다.
Line 86, Line 112에서 $EventName를 이스케이프 없이 정규식에 삽입하고 있어, 특수문자가 포함되면 다른 섹션까지 매칭될 수 있습니다. 이벤트별 enabled/message 판단이 틀어져 의도치 않은 auto-commit이 발생할 수 있습니다.
수정 제안
+ $escapedEventName = [regex]::Escape($EventName)
foreach ($line in Get-Content $configFile) {
@@
- if ($line -match "^\s+${EventName}:") {
+ if ($line -match "^\s+${escapedEventName}:") {
$inEvent = $true
continue
}
@@
- $hasEventKey = Select-String -Path $configFile -Pattern "^\s*${EventName}:" -Quiet
+ $hasEventKey = Select-String -Path $configFile -Pattern "^\s*${escapedEventName}:" -QuietAlso applies to: 112-113
🧰 Tools
🪛 PSScriptAnalyzer (1.25.0)
[warning] Missing BOM encoding for non-ASCII encoded file 'auto-commit.ps1'
(PSUseBOMForUnicodeEncodedFile)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/extensions/git/scripts/powershell/auto-commit.ps1 around lines 86 -
87, Escape the $EventName before inserting it into regex matches to avoid
special-character misinterpretation: replace usages where you build regexes like
$line -match "^\s+${EventName}:" and the later match for message (the patterns
around lines using $EventName and -match) with a version that uses
[regex]::Escape($EventName) (or equivalent) so the literal event name is
matched; update both occurrences (the initial event header match and the
subsequent message/enabled checks) to use the escaped value.
| if [[ -n "${SPECIFY_FEATURE_DIRECTORY:-}" ]]; then | ||
| feature_dir="$SPECIFY_FEATURE_DIRECTORY" | ||
| # Normalize relative paths to absolute under repo root | ||
| [[ "$feature_dir" != /* ]] && feature_dir="$repo_root/$feature_dir" | ||
| elif [[ -f "$repo_root/.specify/feature.json" ]]; then | ||
| # Shared, set -e-safe parser: jq -> python3 -> grep/sed. Returns empty on | ||
| # missing/unparseable/unset so we fall through to the branch-prefix lookup. | ||
| local _fd | ||
| _fd=$(read_feature_json_feature_directory "$repo_root") | ||
| if [[ -n "$_fd" ]]; then | ||
| feature_dir="$_fd" | ||
| # Normalize relative paths to absolute under repo root | ||
| [[ "$feature_dir" != /* ]] && feature_dir="$repo_root/$feature_dir" | ||
| elif ! feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch"); then | ||
| echo "ERROR: Failed to resolve feature directory" >&2 | ||
| return 1 | ||
| fi | ||
| elif ! feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch"); then | ||
| echo "ERROR: Failed to resolve feature directory" >&2 | ||
| return 1 | ||
| fi |
There was a problem hiding this comment.
FEATURE_DIR가 저장소 밖으로 빠질 수 있습니다.
SPECIFY_FEATURE_DIRECTORY나 .specify/feature.json에 ../... 또는 절대 경로가 들어오면 그대로 신뢰합니다. 그 결과 뒤쪽 스크립트들이 저장소 외부 경로에 mkdir/cp/touch를 수행할 수 있어서, 로컬 파일을 의도치 않게 덮어쓸 수 있습니다. 정규화한 뒤 반드시 "$repo_root"/ 하위인지 확인하고, 아니면 실패시키는 쪽이 안전합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/scripts/bash/common.sh around lines 268 - 288, The current
resolution of feature_dir (from SPECIFY_FEATURE_DIRECTORY,
read_feature_json_feature_directory, or find_feature_dir_by_prefix) does not
enforce that the final path is inside repo_root; a malicious or relative value
(../ or absolute) can escape the repo and allow unsafe file operations. After
any assignment to feature_dir (including the branches using
SPECIFY_FEATURE_DIRECTORY, the read_feature_json_feature_directory result, and
the find_feature_dir_by_prefix fallback) normalize to an absolute path and then
validate that feature_dir is a descendant of repo_root (e.g. by resolving both
to absolute, canonical paths and ensuring feature_dir starts with
"$repo_root/"); if validation fails, print an error and return non‑zero instead
of continuing. Ensure this check is applied to the code paths using
variables/functions: SPECIFY_FEATURE_DIRECTORY,
read_feature_json_feature_directory, find_feature_dir_by_prefix, feature_dir,
repo_root, and current_branch.
| --number) | ||
| if [ $((i + 1)) -gt $# ]; then | ||
| echo 'Error: --number requires a value' >&2 | ||
| exit 1 | ||
| fi | ||
| i=$((i + 1)) | ||
| next_arg="${!i}" | ||
| if [[ "$next_arg" == --* ]]; then | ||
| echo 'Error: --number requires a value' >&2 | ||
| exit 1 | ||
| fi | ||
| BRANCH_NUMBER="$next_arg" | ||
| ;; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "[core script]"
sed -n '39,55p' .specify/scripts/bash/create-new-feature.sh
echo
echo "[bash arithmetic reproduction]"
if bash -lc 'BRANCH_NUMBER=foo; printf "%03d\n" "$((10#$BRANCH_NUMBER))"'; then
echo "unexpected: non-numeric input was accepted"
else
echo "ok: non-numeric input is rejected later by Bash arithmetic, not by CLI validation"
fiRepository: THIP-TextHip/THIP-Server
Length of output: 882
🏁 Script executed:
# Find where BRANCH_NUMBER is used in the core script
rg '10#\$BRANCH_NUMBER|BRANCH_NUMBER' .specify/scripts/bash/create-new-feature.sh -n
# Also look for the extension script variant to compare
find .specify/scripts/bash -name "*extension*" -o -name "*extend*" | head -20Repository: THIP-TextHip/THIP-Server
Length of output: 563
🏁 Script executed:
# List all bash scripts in the specified directory to find the extension variant
ls -la .specify/scripts/bash/Repository: THIP-TextHip/THIP-Server
Length of output: 516
🏁 Script executed:
# Search for --number option in all bash scripts to find the extension variant
rg '\-\-number' .specify/scripts/bash/ -A 5
# Also check if there are any other feature creation or extension scripts elsewhere
find . -name "*feature*" -o -name "*extension*" | grep -E '\.(sh|bash)$' | head -20Repository: THIP-TextHip/THIP-Server
Length of output: 5012
🏁 Script executed:
# Find and examine the --number option handling in the extension variant
rg '\-\-number' ./.specify/extensions/git/scripts/bash/create-new-feature.sh -A 15 | head -40Repository: THIP-TextHip/THIP-Server
Length of output: 2089
--number 입력을 여기서 바로 숫자 검증하세요.
현재 코드에서는 숫자 검증이 없어서 --number foo가 뒤쪽의 10#$BRANCH_NUMBER 산술 확장(299번 줄)에서 오류로 종료됩니다: bash: line 1: 10#foo: value too great for base. 확장 스크립트(./.specify/extensions/git/scripts/bash/create-new-feature.sh)는 이미 이 검증을 구현하고 있으므로, 코어 스크립트에서도 동일하게 적용하면 일관성 있는 사용자 경험을 제공할 수 있습니다.
제안 수정
--number)
if [ $((i + 1)) -gt $# ]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
i=$((i + 1))
next_arg="${!i}"
if [[ "$next_arg" == --* ]]; then
echo 'Error: --number requires a value' >&2
exit 1
fi
BRANCH_NUMBER="$next_arg"
+ if [[ ! "$BRANCH_NUMBER" =~ ^[0-9]+$ ]]; then
+ echo 'Error: --number must be a non-negative integer' >&2
+ exit 1
+ fi
;;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/scripts/bash/create-new-feature.sh around lines 39 - 51, When
handling the --number option (the branch-number parsing block that assigns
BRANCH_NUMBER from next_arg), validate that next_arg is a numeric string before
assigning it to BRANCH_NUMBER; if it fails (e.g. not matching a digits-only
regex), print the same error and exit as when the value is missing.
Specifically, in the block that uses i, next_arg and sets BRANCH_NUMBER, add a
numeric check (digits-only, e.g. /^[0-9]+$/) and reject non-numeric values to
avoid the later arithmetic expansion error (10#$BRANCH_NUMBER) — mirror the
validation used in the extension script for consistency.
| # Copy plan template if it exists | ||
| TEMPLATE=$(resolve_template "plan-template" "$REPO_ROOT") || true | ||
| if [[ -n "$TEMPLATE" ]] && [[ -f "$TEMPLATE" ]]; then | ||
| cp "$TEMPLATE" "$IMPL_PLAN" | ||
| echo "Copied plan template to $IMPL_PLAN" | ||
| else | ||
| echo "Warning: Plan template not found" | ||
| # Create a basic plan file if template doesn't exist | ||
| touch "$IMPL_PLAN" | ||
| fi |
There was a problem hiding this comment.
기존 plan.md를 매번 덮어씁니다.
이 상태로 /speckit.plan을 다시 실행하면 사용자가 수정한 계획이 그대로 사라집니다. 파일이 없을 때만 템플릿을 복사하고, 재초기화가 필요하면 --force 같은 명시적 옵션으로 분리하는 편이 안전합니다.
제안 수정
-TEMPLATE=$(resolve_template "plan-template" "$REPO_ROOT") || true
-if [[ -n "$TEMPLATE" ]] && [[ -f "$TEMPLATE" ]]; then
- cp "$TEMPLATE" "$IMPL_PLAN"
- echo "Copied plan template to $IMPL_PLAN"
-else
- echo "Warning: Plan template not found"
- # Create a basic plan file if template doesn't exist
- touch "$IMPL_PLAN"
-fi
+if [[ ! -f "$IMPL_PLAN" ]]; then
+ TEMPLATE=$(resolve_template "plan-template" "$REPO_ROOT") || true
+ if [[ -n "$TEMPLATE" ]] && [[ -f "$TEMPLATE" ]]; then
+ cp "$TEMPLATE" "$IMPL_PLAN"
+ echo "Copied plan template to $IMPL_PLAN"
+ else
+ echo "Warning: Plan template not found"
+ touch "$IMPL_PLAN"
+ fi
+fi🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/scripts/bash/setup-plan.sh around lines 43 - 52, The current
setup-plan.sh unconditionally overwrites IMPL_PLAN using TEMPLATE
(TEMPLATE=$(resolve_template "plan-template" "$REPO_ROOT") ... cp "$TEMPLATE"
"$IMPL_PLAN"), which destroys user edits; change the logic in setup-plan.sh to
only copy the template when IMPL_PLAN does not exist or when an explicit force
option is passed (e.g., check a parsed --force flag or env var like FORCE_PLAN),
keep the resolve_template/TEMPLATE check, and if IMPL_PLAN exists and force is
not set skip copying and print a message that the existing plan is preserved;
ensure the code paths reference TEMPLATE, resolve_template, and IMPL_PLAN so
reviewers can find the updated conditional and option parsing.
| scope: | ||
| type: string | ||
| default: "full" | ||
| enum: ["full", "backend-only", "frontend-only"] |
There was a problem hiding this comment.
❓ Verification inconclusive
Script executed:
#!/bin/bash
# Description: scope 입력값이 다른 파일에서 참조되는지 검색
rg -n "inputs\.scope|SCOPE|scope" .specify/ .claude/ --type yaml --type md -C 2Repository: THIP-TextHip/THIP-Server
Repository: THIP-TextHip/THIP-Server
Exit code: 0
stdout:
.claude/skills/speckit-tasks/SKILL.md-93- - Parallel opportunities identified
.claude/skills/speckit-tasks/SKILL.md-94- - Independent test criteria for each story
.claude/skills/speckit-tasks/SKILL.md:95: - Suggested MVP scope (typically just User Story 1)
.claude/skills/speckit-tasks/SKILL.md-96- - Format validation: Confirm ALL tasks follow the checklist format (checkbox, ID, labels, file paths)
.claude/skills/speckit-tasks/SKILL.md-97-
--
.claude/skills/speckit-specify/SKILL.md-120- - Make informed guesses based on context and industry standards
.claude/skills/speckit-specify/SKILL.md-121- - Only mark with [NEEDS CLARIFICATION: specific question] if:
.claude/skills/speckit-specify/SKILL.md:122: - The choice significantly impacts feature scope or user experience
.claude/skills/speckit-specify/SKILL.md-123- - Multiple reasonable interpretations exist with different implications
.claude/skills/speckit-specify/SKILL.md-124- - No reasonable default exists
.claude/skills/speckit-specify/SKILL.md-125- - **LIMIT: Maximum 3 [NEEDS CLARIFICATION] markers total**
.claude/skills/speckit-specify/SKILL.md:126: - Prioritize clarifications by impact: scope > security/privacy > user experience > technical details
.claude/skills/speckit-specify/SKILL.md-127- 4. Fill User Scenarios & Testing section
.claude/skills/speckit-specify/SKILL.md-128- If no clear user flow: ERROR "Cannot determine user scenarios"
--
.claude/skills/speckit-specify/SKILL.md-196- - **If [NEEDS CLARIFICATION] markers remain**:
.claude/skills/speckit-specify/SKILL.md-197- 1. Extract all [NEEDS CLARIFICATION: ...] markers from the spec
.claude/skills/speckit-specify/SKILL.md:198: 2. **LIMIT CHECK**: If more than 3 markers exist, keep only the 3 most critical (by scope/security/UX impact) and make informed guesses for the rest
.claude/skills/speckit-specify/SKILL.md-199- 3. For each clarification needed (max 3), present options to user in this format:
.claude/skills/speckit-specify/SKILL.md-200-
--
.claude/skills/speckit-specify/SKILL.md-289-2. **Document assumptions**: Record reasonable defaults in the Assumptions section
.claude/skills/speckit-specify/SKILL.md-290-3. **Limit clarifications**: Maximum 3 [NEEDS CLARIFICATION] markers - use only for critical decisions that:
.claude/skills/speckit-specify/SKILL.md:291: - Significantly impact feature scope or user experience
.claude/skills/speckit-specify/SKILL.md-292- - Have multiple reasonable interpretations with different implications
.claude/skills/speckit-specify/SKILL.md-293- - Lack any reasonable default
.claude/skills/speckit-specify/SKILL.md:294:4. **Prioritize clarifications**: scope > security/privacy > user experience > technical details
.claude/skills/speckit-specify/SKILL.md-295-5. **Think like a tester**: Every vague requirement should fail the "testable and unambiguous" checklist item
.claude/skills/speckit-specify/SKILL.md-296-6. **Common areas needing clarification** (only if no reasonable default exists):
.claude/skills/speckit-specify/SKILL.md:297: - Feature scope and boundaries (include/exclude specific use cases)
.claude/skills/speckit-specify/SKILL.md-298- - User types and permissions (if multiple conflicting interpretations possible)
.claude/skills/speckit-specify/SKILL.md-299- - Security/compliance requirements (when legally/financially significant)
--
.claude/skills/speckit-constitution/SKILL.md-85-4. Consistency propagation checklist (convert prior checklist into active validations):
.claude/skills/speckit-constitution/SKILL.md-86- - Read `.specify/templates/plan-template.md` and ensure any "Constitution Check" or rules align with updated principles.
.claude/skills/speckit-constitution/SKILL.md:87: - Read `.specify/templates/spec-template.md` for scope/requirements alignment—update if constitution adds/removes mandatory sections or constraints.
.claude/skills/speckit-constitution/SKILL.md-88- - Read `.specify/templates/tasks-template.md` and ensure task categorization reflects new or removed principle-driven task types (e.g., observability, versioning, testing discipline).
.claude/skills/speckit-constitution/SKILL.md-89- - Read each command file in `.specify/templates/commands/*.md` (including this one) to verify no outdated references (agent-specific names like CLAUDE only) remain when generic guidance is required.
--
.claude/skills/speckit-clarify/SKILL.md-74- Functional Scope & Behavior:
.claude/skills/speckit-clarify/SKILL.md-75- - Core user goals & success criteria
.claude/skills/speckit-clarify/SKILL.md:76: - Explicit out-of-scope declarations
.claude/skills/speckit-clarify/SKILL.md-77- - User roles / personas differentiation
.claude/skills/speckit-clarify/SKILL.md-78-
--
.specify/templates/spec-template.md-127-
.specify/templates/spec-template.md-128-- [Assumption about target users, e.g., "Users have stable internet connectivity"]
.specify/templates/spec-template.md:129:- [Assumption about scope boundaries, e.g., "Mobile support is out of scope for v1"]
.specify/templates/spec-template.md-130-- [Assumption about data/environment, e.g., "Existing authentication system will be reused"]
.specify/templates/spec-template.md-131-- [Dependency on existing system/service, e.g., "Requires access to the existing user profile API"]
--
.claude/skills/speckit-checklist/SKILL.md-92- 2. Cluster signals into candidate focus areas (max 4) ranked by relevance.
.claude/skills/speckit-checklist/SKILL.md-93- 3. Identify probable audience & timing (author, reviewer, QA, release) if not explicit.
.claude/skills/speckit-checklist/SKILL.md:94: 4. Detect missing dimensions: scope breadth, depth/rigor, risk emphasis, exclusion boundaries, measurable acceptance criteria.
.claude/skills/speckit-checklist/SKILL.md-95- 5. Formulate questions chosen from these archetypes:
.claude/skills/speckit-checklist/SKILL.md-96- - Scope refinement (e.g., "Should this include integration touchpoints with X and Y or stay limited to local module correctness?")
--
.claude/skills/speckit-checklist/SKILL.md-99- - Audience framing (e.g., "Will this be used by the author only or peers during PR review?")
.claude/skills/speckit-checklist/SKILL.md-100- - Boundary exclusion (e.g., "Should we explicitly exclude performance tuning items this round?")
.claude/skills/speckit-checklist/SKILL.md:101: - Scenario class gap (e.g., "No recovery flows detected—are rollback / partial failure paths in scope?")
.claude/skills/speckit-checklist/SKILL.md-102-
.claude/skills/speckit-checklist/SKILL.md-103- Question formatting rules:
--
.claude/skills/speckit-checklist/SKILL.md-105- - Limit to A–E options maximum; omit table if a free-form answer is clearer
.claude/skills/speckit-checklist/SKILL.md-106- - Never ask the user to restate what they already said
.claude/skills/speckit-checklist/SKILL.md:107: - Avoid speculative categories (no hallucination). If uncertain, ask explicitly: "Confirm whether X belongs in scope."
.claude/skills/speckit-checklist/SKILL.md-108-
.claude/skills/speckit-checklist/SKILL.md-109- Defaults when interaction impossible:
--
.claude/skills/speckit-checklist/SKILL.md-121-
.claude/skills/speckit-checklist/SKILL.md-122-4. **Load feature context**: Read from FEATURE_DIR:
.claude/skills/speckit-checklist/SKILL.md:123: - spec.md: Feature requirements and scope
.claude/skills/speckit-checklist/SKILL.md-124- - plan.md (if exists): Technical details, dependencies
.claude/skills/speckit-checklist/SKILL.md-125- - tasks.md (if exists): Implementation tasks
--
.claude/skills/speckit-analyze/SKILL.md-63-**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
.claude/skills/speckit-analyze/SKILL.md-64-
.claude/skills/speckit-analyze/SKILL.md:65:**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit-analyze`.
.claude/skills/speckit-analyze/SKILL.md-66-
.claude/skills/speckit-analyze/SKILL.md-67-## Execution Steps
Script executed:
cat .specify/workflows/speckit/workflow.ymlRepository: THIP-TextHip/THIP-Server
Repository: THIP-TextHip/THIP-Server
Exit code: 0
stdout:
schema_version: "1.0"
workflow:
id: "speckit"
name: "Full SDD Cycle"
version: "1.0.0"
author: "GitHub"
description: "Runs specify → plan → tasks → implement with review gates"
requires:
speckit_version: ">=0.7.2"
integrations:
any: ["copilot", "claude", "gemini"]
inputs:
spec:
type: string
required: true
prompt: "Describe what you want to build"
integration:
type: string
default: "copilot"
prompt: "Integration to use (e.g. claude, copilot, gemini)"
scope:
type: string
default: "full"
enum: ["full", "backend-only", "frontend-only"]
steps:
- id: specify
command: speckit.specify
integration: "{{ inputs.integration }}"
input:
args: "{{ inputs.spec }}"
- id: review-spec
type: gate
message: "Review the generated spec before planning."
options: [approve, reject]
on_reject: abort
- id: plan
command: speckit.plan
integration: "{{ inputs.integration }}"
input:
args: "{{ inputs.spec }}"
- id: review-plan
type: gate
message: "Review the plan before generating tasks."
options: [approve, reject]
on_reject: abort
- id: tasks
command: speckit.tasks
integration: "{{ inputs.integration }}"
input:
args: "{{ inputs.spec }}"
- id: implement
command: speckit.implement
integration: "{{ inputs.integration }}"
input:
args: "{{ inputs.spec }}"
워크플로우에서 scope 입력값이 사용되지 않음.
scope 입력값이 라인 23-26에서 정의되어 있지만, 워크플로우의 어떤 단계(steps)에서도 참조되지 않습니다. 현재 모든 단계는 {{ inputs.integration }}과 {{ inputs.spec }}만 사용하며, {{ inputs.scope }}는 참조하지 않습니다. 사용자가 "backend-only" 또는 "frontend-only"를 지정해도 실제 워크플로우 동작에는 영향을 미치지 않습니다. 이 파라미터를 제거하거나 실제 워크플로우 로직에 통합해야 합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.specify/workflows/speckit/workflow.yml around lines 23 - 26, 워크플로우에 선언된 입력값
`scope`(enum ["full","backend-only","frontend-only"])가 실제로 사용되지 않아 동작에 영향이 없으니,
either remove the `scope` input or wire it into the existing steps by using `{{
inputs.scope }}` in conditional expressions; specifically update the steps that
currently reference `{{ inputs.integration }}` and `{{ inputs.spec }}` to
include `if`/`when` conditions (e.g., check `{{ inputs.scope }} ==
'backend-only'`, `== 'frontend-only'` or `== 'full'`) so backend-only tasks skip
in frontend-only runs and vice versa, or delete the `scope` declaration if you
choose not to support scoping.
| <!-- SPECKIT START --> | ||
| For additional context about technologies to be used, project structure, | ||
| shell commands, and other important information, read the current plan | ||
| <!-- SPECKIT END --> |
There was a problem hiding this comment.
"current plan" 위치가 명시되지 않았습니다.
3번 라인에서 "read the current plan"이라고 안내하고 있으나, 구체적인 파일 경로나 위치가 명시되지 않았습니다. Claude Code 에이전트가 이 안내를 읽을 때 실제로 어디에서 plan을 찾아야 할지 알 수 없어 컨텍스트 제공 목적을 달성하기 어렵습니다.
다음 중 하나로 개선을 권장합니다:
- 정확한 파일 경로 명시 (예:
.specify/plan.md또는.specify/workflows/speckit/plan.md) - Feature별 동적 경로 안내 (예: "read the current plan in
.specify/features/{feature-id}/plan.md") - 또는 Spec Kit 컨벤션상 암묵적으로 정해진 위치가 있다면 주석으로 설명 추가
제안: 구체적인 경로 명시
<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
-shell commands, and other important information, read the current plan
+shell commands, and other important information, read the current plan at
+`.specify/plan.md` (or the plan.md file in the active feature directory).
<!-- SPECKIT END -->🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CLAUDE.md` around lines 1 - 4, 문구 "read the current plan" in CLAUDE.md is
ambiguous; update that line to point to a concrete plan location (e.g. replace
or augment "read the current plan" with a specific path like `.specify/plan.md`
or a dynamic pattern such as `.specify/features/{feature-id}/plan.md`), or add a
short comment explaining the Spec Kit convention if the path is implicit,
ensuring the exact phrase "read the current plan" is modified so Claude knows
where to find the plan.
Summary
도입 배경
PRD/스펙 문서가 0인 브라운필드 상황에서 정형화 필요. BMAD/OpenSpec/GSD를 검토했고 브라운필드 + 백엔드 3인팀 + 한국어 문서에 가장 잘 맞는 Spec Kit으로 결정.
무엇이 추가되는가
.specify/.specify/memory/constitution.md.claude/skills/speckit-*CLAUDE.md.gitignore*.yml룰이.specify메타 yml까지 가리는 문제 해결 (!.specify/**/*.yml예외)헌법 핵심 결정 (
.specify/memory/constitution.md참고)6개 원칙:
TODO(JACOCO_THRESHOLD))TODO(K6_THRESHOLDS))거버넌스:
Spec Kit 워크플로우 사용법
새 기능/도메인 정형화 시:
설치 (로컬):
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@v0.8.11후속 PR
Test plan
.gitignore변경이 기존 워크플로우(.github/workflows/*.yml 추적)에 영향 없는지 확인specify init결과물 구조 확인하고 싶은 리뷰어는 README 절차 따라 시도Summary by CodeRabbit
릴리스 노트
새로운 기능
설정 및 워크플로우